package org.awaitility.core;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * Please don't use this class directly, it's for internal purposes only and will be moved/renamed without notice!
 */
public class InternalExecutorServiceFactory {

    /**
     * @return A executor service that executes tasks in the caller's thread
     */
    public static ExecutorService sameThreadExecutorService() {
        return new SameThreadExecutorService();
    }

    /**
     * Creates an executor service that creates thread's based on the <code>thread supplier</code>
     * @param threadSupplier The thread supplier
     * @return An executor service that will use the thread created by the <code>threadSupplier</code> when polling
     */
    public static ExecutorService create(final Function<Runnable, Thread> threadSupplier) {
        if (threadSupplier == null) {
            throw new IllegalArgumentException("Condition evaluation thread supplier cannot be null");
        }
        return create((runnable, __) -> threadSupplier.apply(runnable), null);
    }

    /**
     * Creates an executor services that creates thread's based on the <code>thread supplier</code>.
     * The first argument to the <code>threadSupplier</code> is the Runnable (the condition that will be evaluated).
     * The second argument is the default thread name generated by Awaitility.
     * @param threadSupplier The thread supplier
     * @return An executor service that will use the thread created by the <code>threadSupplier</code> when polling
     */
    public static ExecutorService create(final BiFunction<Runnable, String, Thread> threadSupplier, final String alias) {
        if (threadSupplier == null) {
            throw new IllegalArgumentException("Condition evaluation thread supplier cannot be null");
        }
        return Executors.newSingleThreadExecutor(r -> {
            final String threadName = generateDefaultThreadName(alias);
            return threadSupplier.apply(r, threadName);
        });
    }

    private static String generateDefaultThreadName(String alias) {
        return alias == null ? "awaitility-thread" : "awaitility[" + alias + "]";
    }
}
